package gameoflife;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.sameInstance;

import java.util.List;

import org.junit.Test;

public class GridTest {

	@Test
	public void createNewGridWithGivenSize() throws Exception {
		Grid grid = new Grid(1, 1);
		assertThat(grid.rows(), equalTo(1));
		assertThat(grid.columns(), equalTo(1));
	}

	@Test
	public void cellHasNoNeighbours() throws Exception {
		Grid grid = new Grid(1, 1);
		Cell cell = new Cell(0, 0);
		grid.addCells(cell);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, is(empty()));
	}

	@Test
	public void cellHasANeighbourOnTheRightSide() throws Exception {
		Grid grid = new Grid(2, 1);
		Cell cell = new Cell(0, 0);
		Cell neighbour = new Cell(1, 0);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(1));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasANeighbourOnTheLeftSide() throws Exception {
		Grid grid = new Grid(2, 1);
		Cell cell = new Cell(1, 0);
		Cell neighbour = new Cell(0, 0);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(1));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasAboveANeighbour() throws Exception {
		Grid grid = new Grid(1, 2);
		Cell cell = new Cell(0, 0);
		Cell neighbour = new Cell(0, 1);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(1));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasBelowANeighbour() throws Exception {
		Grid grid = new Grid(1, 2);
		Cell cell = new Cell(0, 1);
		Cell neighbour = new Cell(0, 0);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(1));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasANeighbourOnTheRightTopDiagonal() throws Exception {
		Grid grid = new Grid(2, 2);
		Cell cell = new Cell(0, 0);
		Cell neighbour = new Cell(1, 1);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(3));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasANeighbourOnTheRightBottomDiagonal() throws Exception {
		Grid grid = new Grid(2, 2);
		Cell cell = new Cell(0, 1);
		Cell neighbour = new Cell(1, 0);
		grid.addCells(cell, neighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(3));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void cellHasTwoNeighbours() throws Exception {
		Grid grid = new Grid(3, 3);
		Cell cell = new Cell(1, 1);
		Cell firstNeighbour = new Cell(0, 0);
		Cell secondNeighbour = new Cell(1, 2);
		grid.addCells(cell, firstNeighbour, secondNeighbour);
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(8));
		assertThat(neighbours, hasItems(firstNeighbour, secondNeighbour));
	}

	@Test
	public void bigGridHasOneNeighbour() throws Exception {
		Grid grid = new Grid(5, 5);
		Cell cell = new Cell(2, 2);
		Cell neighbour = new Cell(1, 2);
		grid.addCells(cell, neighbour, new Cell(0, 0), new Cell(4, 4),
				new Cell(0, 4), new Cell(4, 2));
		List<Cell> neighbours = grid.getNeighboursForCell(cell);
		assertThat(neighbours, hasSize(8));
		assertThat(neighbours, hasItem(neighbour));
	}

	@Test
	public void returnsCellAtGivenPosition() throws Exception {
		Grid grid = new Grid(5, 5);
		Cell cell = new Cell(1, 2);
		grid.addCells(cell);
		Cell found = grid.getCellAt(1, 2);
		assertThat(found, sameInstance(cell));
	}

}
